package main

import ( "io"; "os")

import "fmt"

import "code.google.com/p/x-go-binding/xgb"

import "code.google.com/p/freetype-go/freetype/raster"
import "panel"
import "edit"
import "header"
import "frame"

func main() {
	c, err := xgb.Dial(os.Getenv("DISPLAY"))
	if err != nil {
		fmt.Printf("cannot connect: %v\n", err)
		os.Exit(1)
	}
	//    
	loop(c)
}

type ignore int

func (ignore) Do(command string) {}

func put32(buf []byte, v uint32) {
	buf[0] = byte(v)
	buf[1] = byte(v >> 8)
	buf[2] = byte(v >> 16)
	buf[3] = byte(v >> 24)
}

func fix32(x, y int) panel.Point {
	return panel.Point{raster.Fix32(x << 8), raster.Fix32(y << 8)}
}

func loop(con *xgb.Conn) {
	//
	km, err := con.GetKeyboardMapping(8, 255-8+1)
	if err != nil {
		fmt.Println("keyboard mapping error: ", err)
	}
	// fmt.Println("KeysymsPerKeycode", km.KeysymsPerKeycode
	//
	di := panel.NewDrawInfo()
	cols := 120
	rows := 28
	width, height := di.CellsToPixels(rows, cols)
	//
	c := &panel.ScrollablePanel{}
	h := header.NewHeaderPanel(di, nil, nil)
	e := edit.NewEditCompilePanel(di, c, h)
	h.Other = e.Edit
	h.Do = e.Edit
	f := frame.NewFrame(e.Edit, e, c, h)
	s := panel.NewShelf(f, &panel.Common{})
	wp := panel.NewWindowPanel(con, di, s, width, height)
	wp.Resize(panel.Size(fix32(width, height)), panel.Point{})
	wp.Refresh()
	//
	var focus panel.View = e.Edit
	wp.Cursor(fix32(20, 20))
	for {
		wp.ShowCursor()
		reply, err := con.WaitForEvent()
		wp.HideCursor()
		if err != nil {
			fmt.Printf("boom: %v\n", err)
			if err == io.EOF {
				return
			}
		}
		switch event := reply.(type) {

		case xgb.KeyPressEvent:
			// one day ...
			// fmt.Println( ">> key press event" )

		case xgb.KeyReleaseEvent:
			shift := int(event.State & 1)
			// fmt.Println(">> state = ", event.State)
			d := int(event.Detail - 8)
			// fmt.Println("detail: ", d, "; leength keysyms: ", len(km.Keysyms))
			keysym := km.Keysyms[d*int(km.KeysymsPerKeycode)+shift]
			key := int(keysym)
			if event.State&4 != 0 {
				key = key - 'a' + 1
			}
			fmt.Printf("passing key %v to panel %T\n", key, focus)
			newFocus := focus.Key(key)
			if newFocus != nil {
				focus = newFocus
			}

		case xgb.MotionNotifyEvent:
			x, y := event.EventX, event.EventY
			// panel.Log("MotionNotify: xy = ", fix32(int(x), int(y)))
			inside := wp.At(fix32(int(x), int(y)))
			if inside != focus { // <<x============================================
				panel.Log("Change of Focus")
				focus.LoseFocus()
				focus = inside
				focus.GainFocus(fix32(int(x), int(y)))
			}

		case xgb.ButtonPressEvent:
			// one day ...

		case xgb.ButtonReleaseEvent:
			f := wp.FocusForClick(fix32(int(event.EventX), int(event.EventY)))
			if f != nil {
				focus = f
			}

		case xgb.ConfigureNotifyEvent:
			wp.Resize(panel.Size(fix32(int(event.Width)-20, int(event.Height)-20)), panel.Point{0, 0})

		case xgb.ExposeEvent:
			if event.Count == 0 {
				wp.Refresh()
			}
			// col, line, _ := curses.MouseEvent()
			//    focus = wp.FocusForClick(line, col)

		default:
			fmt.Printf(">> event %T %v\n", reply, reply)
		}
	}
}
